﻿using MongoDB.Driver;
using System;
using System.Collections.Generic;
using MongoDB.Driver.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Linq;
using System.Threading;
using Lynn.Infastructure.Repository.BaseEntity;
using Microsoft.Extensions.DependencyInjection;

namespace Lynn.Infastructure.Repository.MongoDB
{
    [AppIgnore]
    public class MongoBaseRepository<T> : IMongoBaseRepository<T> where T : Entity
    {
        protected IMongoDatabase Database { get; private set; }
        protected IMongoCollection<T> _collection;
        public MongoBaseRepository(MongoBaseContext context)
        {
            Database = context.Client.GetDatabase(context.DatabaseName);
            _collection = Database.GetCollection<T>(typeof(T).Name);

        }
        public async Task<bool> Delete(T entity)
        {
            var filterBuilder = Builders<T>.Filter;
            var filter = filterBuilder.Eq("_id", entity.Id);
            var deleteResult = await _collection.DeleteOneAsync(filter);
            return (int)deleteResult.DeletedCount > 0;
        }

        public async Task<bool> Instert(T entity)
        {
            try
            {
                await _collection.InsertOneAsync(entity);
                return true;
            }
            catch
            {
                return false;
            };
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> where)
        {
            return _collection.AsQueryable().Where(where);
        }

        public IList<T> GetListPage(int page, int pageSize, out int totalPage, out int totalCount, Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool orderByasc = true)
        {
            if (page < 1)
            {
                throw new Exception("页码从1开始计算");
            }
            var query = _collection.AsQueryable().Where(where);
            if (orderByasc)
            {
                query = query.OrderBy(order);
            }
            else
            {
                query = query.OrderByDescending(order);
            }
            totalCount = query.Count();
            totalPage = (int)Math.Ceiling(totalCount / pageSize * 1.0d);
            return query.Skip(pageSize * (page - 1)).Take(pageSize).ToList();
        }

        public async Task<bool> Update(T entity)
        {
            var result = await _collection.ReplaceOneAsync(x => x.Id == entity.Id, entity);
            return (int)result.MatchedCount > 0;
        }

        public async Task<bool> Instert(IEnumerable<T> entities)
        {
            try
            {
                await _collection.InsertManyAsync(entities);
                return true;
            }
            catch
            {
                return false;
            };
        }

        public async Task<bool> Delete(IEnumerable<T> entities)
        {
            var filterBuilder = Builders<T>.Filter;
            var ids = entities.Select(x => x.Id).ToList();
            var filter = filterBuilder.Where(x => ids.Contains(x.Id));
            var deleteResult = await _collection.DeleteManyAsync(filter);
            return (int)deleteResult.DeletedCount > 0;
        }

        public async Task<bool> Update(IEnumerable<T> entities)
        {
            foreach (var entity in entities) {
                await _collection.ReplaceOneAsync(x => x.Id == entity.Id, entity);
            }
            return true;
        }

        public async Task<IList<T>> GetList(Expression<Func<T, bool>> where)
        {
            return await _collection.AsQueryable().Where(where).ToListAsync();
        }

        public async Task<bool> Update(Expression<Func<T, bool>> where, object param)
        {
            var entiteis = await GetList(where);
            long count = 0;
            foreach (var entity in entiteis)
            {
                var ps = entity.GetType().GetProperties();
                foreach (var item in ps)
                {
                    var t = param.GetType().GetProperty(item.Name);
                    if (t == null)
                    {
                        continue;
                    }
                    var value = t.GetValue(param);
                    item.SetValue(entity, value);
                }
                var res=await _collection.ReplaceOneAsync(x => x.Id == entity.Id, entity);
                count += res.MatchedCount;
            }
            return count > 0;
        }
    }
}
